package com.wjx.demo.authorize

import kotlin.properties.Delegates
import kotlin.reflect.KProperty

interface A {
    fun say()
}

class AA : A {
    override fun say() {
        println("AA")
    }
}

//类委托 by 子句表示，将 a 保存在 AAA 的对象实例内部，而且编译器将会生成继承自 A 接口的所有方法, 并将调用转发给 a。
class AAA(a: A) : A by a

//属性委托
//by 关键字之后的表达式就是委托, 属性的 get() 方法(以及set() 方法)将被委托给这个对象的 getValue() 和 setValue() 方法。
// 属性委托不必实现任何接口, 但必须提供 getValue() 函数(对于 var属性,还需要 setValue() 函数)。
class B {
    var s: String by BB()
}

//该类需要包含 getValue() 方法和 setValue() 方法，且参数 thisRef 为进行委托的类的对象，prop 为进行委托的属性的对象。
class BB {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$thisRef 的 ${property.name} 属性赋值为 $value")
    }
}

fun main(args: Array<String>) {
    AAA(AA()).say()   //由于委托，所以AAA自动拥有AA的所有方法
    println(B().s)     // 访问该属性，调用 getValue() 函数
    B().s = "ss"      //  调用 setValue() 函数
    println(B().s)

    //延迟属性 Lazy
    val s: String by lazy {
        println("aaaa")
        "a"
    }
    println(s)  //输出 aaa 和 a
    println(s)  //输出 a


    //可观察属性 Observable
    class U {
        var s: String by Delegates.observable("init") {
            property, oldValue, newValue ->
            println("prop:$property,old:$oldValue,new:$newValue")
        }
    }
    U().s = "1"
    U().s = "2"

    //把属性储存在映射中,如果使用 var 属性，需要把 Map 换成 MutableMap：
    class V(map: Map<String, Any?>) {
        val s: String by map
        val i: Int by map
    }

    val v = V(mapOf(
            "s" to "s1",
            "i" to 1
    ))
    println(v.s)
    println(v.i)

    //Not Null
    //notNull 适用于那些无法在初始化阶段就确定属性值的场合，如果属性在赋值前就被访问的话则会抛出异常。
    var b: String by Delegates.notNull<String>()
    b = "s"
    println(b)

    var list = listOf<Int>(1, 2, 3)
    fun gt(i: Int) = i > 1
    list.filter(::gt).forEach { println(it) }
}